package com.glp.work.flow.controller;

import com.alibaba.fastjson.JSON;
import com.glp.common.reponse.BaseResult;
import com.glp.fbs.api.dto.user.PersonInfoDto;
import com.glp.work.flow.client.WfProcessInitiateClient;
import com.glp.work.flow.constant.APICode;
import com.glp.work.flow.dto.request.StartProcessRequestDTO;
import com.glp.work.flow.exception.APIException;
import com.glp.work.flow.exception.WorkflowException;
import com.glp.work.flow.mapper.WfOrderMapper;
import com.glp.work.flow.pojo.WfPlatformDefModle;
import com.glp.work.flow.request.DeleteRuningOrderRequest;
import com.glp.work.flow.request.MessageEventReceivedRequest;
import com.glp.work.flow.request.ProcessInitiateRequest;
import com.glp.work.flow.response.OrderHisInfoResponse;
import com.glp.work.flow.response.OrderStatusResponse;
import com.glp.work.flow.response.ProcessInitiateResponse;
import com.glp.work.flow.service.UserService;
import com.glp.work.flow.service.WfPlatformDefService;
import com.glp.work.flow.service.WfProcessInitiateService;
import com.glp.work.flow.service.WfProcessService;
import com.glp.work.flow.utils.TraceIDUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

/**
 * 外部系统发起工作流
 *
 * @author pengjia
 * @version 2020年3月9日 上午11:53:35
 */
@RestController
@Slf4j
@RequestMapping("/wf/process")
@Api(tags = "外部系统发起工作流")
public class WfProcessInitiateController implements WfProcessInitiateClient {

    @Autowired
    public WfProcessInitiateService wfProcessInitiateService;
    @Autowired
    private WfProcessService wfProcessService;
    @Autowired
    private WfOrderMapper orderMapper;
    @Autowired
    RepositoryService repositoryService;
    @Resource
    private WfPlatformDefService wfPlatformDefService;
    @Resource
    private UserService userService;

    @ApiOperation(value = "发起工作流", notes = "")
    @PostMapping(value = "/initiate", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    @Override
    public BaseResult<ProcessInitiateResponse> processInitate(@RequestBody ProcessInitiateRequest request) {
        if (request == null) {
            return new BaseResult<>(APICode.NULL_PARAMETER.getCode(), "参数为空！");
        }
        log.info("发起工作流请求报文：{}", JSON.toJSONString(request));
        { //APPID合法性校验
            if (!wfProcessInitiateService.validateAppId(request.getAppId())) {
                log.error("APPID不合法！{}", request.getAppId());
                throw new WorkflowException(APICode.INVALID_PARAMETER, "APPID不合法！");
            }
        }
        {
            //校验流程是否可用
            List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionKey(request.getProcDefKey()).list();
            if (CollectionUtils.isNotEmpty(processDefinitions)) {
                Optional<ProcessDefinition> max = processDefinitions.stream().max(Comparator.comparing(ProcessDefinition::getVersion));
                if (max.isPresent()) {
                    ProcessDefinition processDefinition = max.get();
                    if (processDefinition.isSuspended()) {
                        throw new WorkflowException(APICode.INVALID_PARAMETER, processDefinition.getName() + "此流程为禁用状态！" + request.getProcDefKey());
                    }
                }
            } else {
                throw new WorkflowException(APICode.INVALID_PARAMETER, "未找到此流程模板！" + request.getProcDefKey());
            }
        }
        {  //单号必输和单号重复性校验
            if (StringUtils.isNotBlank(request.getOrderId())) {
                {// 外部单号长度校验
                    if (request.getOrderId().length() > 64) {
                        throw new WorkflowException(APICode.INVALID_PARAMETER, "单号长度超64！" + request.getOrderId());
                    }
                }
                {// 判断单号是否重复提交。工单ID+模板ID+系统平台ID
                    wfProcessInitiateService.validateDuplicavteProcess(request.getOrderId(), request.getAppId(), request.getProcDefKey(), request.getBatch());
                }
            } else {
                log.error("ORDERID不能为空！{}", request.getOrderId());
                throw new WorkflowException(APICode.INVALID_PARAMETER, "ORDERID不能为空！" + request.getOrderId());
            }
        }
        {//流程定义key校验
            if (StringUtils.isNotEmpty(request.getProcDefKey())) {
                if (!wfProcessInitiateService.validateProDefKey(request.getProcDefKey())) {
                    log.error("流程定义KEY无效！{}", request.getProcDefKey());
                    throw new WorkflowException(APICode.INVALID_PARAMETER, "流程定义KEY无效！" + request.getProcDefKey());
                }
            } else {
                log.error("ProcDefKey不能为空！{}", request.getProcDefKey());
                throw new WorkflowException(APICode.INVALID_PARAMETER, "ProcDefKey不能为空！" + request.getProcDefKey());
            }
        }
        {//动态表单必输校验
            if (request.getDynamicForm() != null && !request.getDynamicForm().isEmpty()) {
                String validResult = wfProcessInitiateService.validateFormData(request.getProcDefKey(), request.getDynamicForm());
                if (StringUtils.isNotBlank(validResult)) {
                    log.error("表单数据校验不通过！{}", request.getProcDefKey());
                    throw new WorkflowException(APICode.INVALID_PARAMETER, "表单数据校验不通过！" + validResult);
                }
            }
        }

        {//校验index_123 长度
            if (StringUtils.isNoneBlank(request.getIndex_1())) {
                if (request.getIndex_1().length() > 512) {
                    throw new WorkflowException(APICode.DATA_ERROR, "index_1长度过长！" + request.getIndex_1());
                }
            }
            if (StringUtils.isNoneBlank(request.getIndex_2())) {
                if (request.getIndex_2().length() > 512) {
                    throw new WorkflowException(APICode.DATA_ERROR, "index_2长度过长！" + request.getIndex_2());
                }
            }
            if (StringUtils.isNoneBlank(request.getIndex_3())) {
                if (request.getIndex_3().length() > 512) {
                    throw new WorkflowException(APICode.DATA_ERROR, "index_3长度过长！" + request.getIndex_3());
                }
            }
        }

        //开始一个工作流
        StartProcessRequestDTO target = new StartProcessRequestDTO();
        BeanUtils.copyProperties(request, target);
        ProcessInitiateResponse processInitiateResponse = wfProcessInitiateService.processInitiateDoMain(target);
        BaseResult<ProcessInitiateResponse> result = new BaseResult<>(APICode.SUCCESS.getCode(), "发起工作流(或更新工作流信息)成功！" + TraceIDUtils.getLogTraceId(), processInitiateResponse);
        log.info("发起工作流(或更新工作流信息)响应：{}", JSON.toJSONString(result));
        return result;
    }

    @ApiOperation(value = "发起工作流2.0", notes = "")
    @PostMapping(value = "/initiateTwo", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    @Override
    public BaseResult<ProcessInitiateResponse> processInitateTwo(@RequestBody ProcessInitiateRequest request) {
        {
            //校验应用使用流程的权限
            WfPlatformDefModle wfPlatformDefModle = wfPlatformDefService.validateAppIdRole(request.getAppId(), request.getProcDefKey());
            if (wfPlatformDefModle == null) {
                throw new WorkflowException(APICode.INVALID_PARAMETER, "指定流程未授权！" + request.getProcDefKey());
            }
        }
        {
            if (request.getBusinessScopebCode() == null) {
                PersonInfoDto personInfo = userService.getPersonInfo(request.getUserId(), request.getAppId());
                if (personInfo != null) {
                    List<String> businessRangeCodes = personInfo.getBusinessRangeCodes();
                    if (CollectionUtils.isNotEmpty(businessRangeCodes)) {
                        String substring = businessRangeCodes.toString().substring(1, businessRangeCodes.toString().length() - 1);
                        log.info("用户有业务范围...{}", substring);
                        request.setBusinessScopebCode(substring);
                    }
                }
            }
        }
        return processInitate(request);
    }


    @ApiOperation(value = "撤销工单(删除数据)", notes = "")
    @PostMapping(value = "/deleteRuningOrder")
    @ResponseBody
    @Override
    public BaseResult<ProcessInitiateResponse> deleteRuningOrder(@RequestBody DeleteRuningOrderRequest deleteRuningOrderRequest) {
        log.info("撤销工单：{}", deleteRuningOrderRequest);
        if (StringUtils.isBlank(deleteRuningOrderRequest.getAppId())) {
            throw new WorkflowException(APICode.INVALID_PARAMETER, "APPID不能为空！");
        }

        if (StringUtils.isBlank(deleteRuningOrderRequest.getProcessId())) {
            throw new WorkflowException(APICode.INVALID_PARAMETER, "processId不能为空！");
        }
        String processId = wfProcessInitiateService.deleteRuningOrder(deleteRuningOrderRequest);
        ProcessInitiateResponse processInitiateResponse = new ProcessInitiateResponse();
        processInitiateResponse.setProcessId(processId);
        BaseResult<ProcessInitiateResponse> result = new BaseResult<>(APICode.SUCCESS.getCode(), "撤销工单成功！" + TraceIDUtils.getLogTraceId(), processInitiateResponse);
        log.info("撤销工单成功：{}", JSON.toJSONString(result));
        return result;
    }

    @ApiOperation(value = "删除此模板下的所有工单", notes = "")
    @PostMapping(value = "/removeOrderByProcDefKey")
    @ResponseBody
    public BaseResult<String> removeOrderByProcDefKey(@RequestParam String prcDefKey) {
        log.info("删除此模板下的所有工单:{}", prcDefKey);
        if (StringUtils.isBlank(prcDefKey)) {
            throw new WorkflowException(APICode.INVALID_PARAMETER, "processId不能为空！");
        }
        wfProcessInitiateService.removeOrderByProcDefKey(prcDefKey);
        BaseResult<String> result = new BaseResult<>(APICode.SUCCESS.getCode(), "删除此模板下的所有工单成功！" + TraceIDUtils.getLogTraceId(), prcDefKey);
        log.info("删除此模板下的所有工单成功：{}", JSON.toJSONString(result));
        return result;
    }


    @ApiOperation(value = "查询工单状态", notes = "")
    @GetMapping(value = "/status/{processId}")
    @ResponseBody
    @Override
    public BaseResult<OrderStatusResponse> queryOrderStatus(@PathVariable(value = "processId") String processId) {
        log.info("查询工单状态请求：{}", processId);
        if (StringUtils.isBlank(processId)) {
            throw new APIException(APICode.DATA_ERROR, "工单ID不能为空！");
        }
        OrderStatusResponse response = wfProcessInitiateService.queryOrderStatus(processId);
        BaseResult<OrderStatusResponse> result = new BaseResult<>(APICode.SUCCESS.getCode(), "查询工单状态成功！" + TraceIDUtils.getLogTraceId(), response);
        log.info("查询工单状态响应：{}", JSON.toJSONString(result));
        return result;
    }

    @ApiOperation(value = "更新驳回工单状态为待审批")
    @GetMapping(value = "/updateStatus/{processId}")
    @ResponseBody
    @Override
    public BaseResult<OrderStatusResponse> updateOrderStatus(@PathVariable(value = "processId") String processId) {
        log.info("更新驳回工单状态为待审批：{}", processId);

        if (StringUtils.isBlank(processId)) {
            throw new APIException(APICode.DATA_ERROR, "工单ID不能为空！");
        }
        OrderStatusResponse response = wfProcessInitiateService.queryOrderStatus(processId);
        if (response == null) {
            throw new APIException(APICode.DATA_ERROR, "未找到指定工单！processId：" + processId);
        } else {
            if (response.getStatus().equals("40")) {
                wfProcessInitiateService.updateOrderStatus(response);
                log.info("更新状态成功：processId：" + processId);
            } else {
                throw new APIException(APICode.DATA_ERROR, "工单未被驳回，不能更新状态！processId：" + processId);
            }
        }
        response.setStatus("待审批");
        BaseResult<OrderStatusResponse> result = new BaseResult<>(APICode.SUCCESS.getCode(), "更新状态成功！" + TraceIDUtils.getLogTraceId(), response);
        return result;
    }

    @ApiOperation(value = "已完成工单历史信息查询", notes = "已完成工单历史信息查询")
    @GetMapping(value = "/his/{orderId}")
    @ResponseBody
    @Override
    public BaseResult<List<OrderHisInfoResponse>> queryOrderHistoryInfo(@PathVariable(value = "orderId") String orderId) {
        log.info("已完成工单历史信息查询请求：{}", orderId);
        if (StringUtils.isBlank(orderId)) {
            throw new APIException(APICode.DATA_ERROR, "工单ID不能为空！");
        }
        List<OrderHisInfoResponse> hisList = wfProcessInitiateService.queryHistoryRecordsByOrderId(orderId);
        BaseResult<List<OrderHisInfoResponse>> result = new BaseResult<>(APICode.SUCCESS.getCode(), "已完成工单历史信息查询成功！" + TraceIDUtils.getLogTraceId(), hisList);
        log.info("已完成工单历史信息查询响应：{}", JSON.toJSONString(result));
        return result;
    }


    @ApiOperation(value = "中间消息通知")
    @PostMapping(value = "/messageEventReceived")
    @ResponseBody
    @Override
    public BaseResult<String> messageEventReceived(@RequestBody MessageEventReceivedRequest messageEventReceivedRequest) {
        log.info("中间消息通知请求：{}", JSON.toJSONString(messageEventReceivedRequest));
        if (StringUtils.isBlank(messageEventReceivedRequest.getExecutionId())) {
            throw new WorkflowException(APICode.INVALID_PARAMETER, "执行ID不能为空！");
        }

        if (StringUtils.isBlank(messageEventReceivedRequest.getProcessId())) {
            throw new WorkflowException(APICode.INVALID_PARAMETER, "processId不能为空！");
        }

        try {
            wfProcessService.messageEventReceived(messageEventReceivedRequest);
            BaseResult<String> baseResult = new BaseResult<>(APICode.SUCCESS.getCode(), "中间消息通知成功！" + TraceIDUtils.getLogTraceId());
            log.info("中间消息通知响应：{}", JSON.toJSONString(baseResult));
            return baseResult;
        } catch (Exception e) {
            log.error("中间消息通知异常,Exception", e);
            return new BaseResult<>(APICode.ERROR.getCode(), "中间消息通知异常！" + TraceIDUtils.getLogTraceId());
        }
    }


    @ApiOperation(value = "工单不通过", notes = "")
    @PostMapping(value = "/auditFail")
    @ResponseBody
    @Override
    public BaseResult<ProcessInitiateResponse> auditFailRuningOrder(@RequestBody DeleteRuningOrderRequest deleteRuningOrderRequest) {
        log.info("工单不通过：{}", deleteRuningOrderRequest);
        if (StringUtils.isBlank(deleteRuningOrderRequest.getAppId())) {
            throw new WorkflowException(APICode.INVALID_PARAMETER, "APPID不能为空！");
        }

        if (StringUtils.isBlank(deleteRuningOrderRequest.getProcessId())) {
            throw new WorkflowException(APICode.INVALID_PARAMETER, "processId不能为空！");
        }
        String processId = wfProcessInitiateService.auditFailRuningOrder(deleteRuningOrderRequest);
        ProcessInitiateResponse processInitiateResponse = new ProcessInitiateResponse();
        processInitiateResponse.setProcessId(processId);
        BaseResult<ProcessInitiateResponse> result = new BaseResult<>(APICode.SUCCESS.getCode(), "工单不通过成功！" + TraceIDUtils.getLogTraceId(), processInitiateResponse);
        log.info("工单不通过成功：{}", JSON.toJSONString(result));
        return result;
    }

}
